package com.tyx.chargingpile.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.tyx.chargingpile.Enum.ServiceMessageEume;
import com.tyx.chargingpile.Enum.ServiceExceptionEume;
import com.tyx.chargingpile.cache.SocketChannelMap;
import com.tyx.chargingpile.handler.ChargingHandler;
import com.tyx.chargingpile.vo.HttpResult;
import com.tyx.chargingpile.vo.PileInfo;
import com.tyx.chargingpile.vo.SocketResponseResult;
import com.tyx.chargingpile.service.ChargingPileService;
import com.tyx.chargingpile.service.HttpAPIService;
import com.tyx.chargingpile.service.MessageService;
import com.tyx.chargingpile.service.exception.ServiceExcep;
import com.tyx.chargingpile.util.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * 电桩注册
 */
@Service("chargingPileRegister")
public class ChargingPileRegister implements ChargingPileService {

    @Value("${chargingback1.url}")
    private String url;
    @Autowired
    HttpAPIService httpAPIService;
    private final static Logger LOGGER = LoggerFactory.getLogger(ChargingPileRegister.class);


    @Override
    public SocketResponseResult execute(ChannelHandlerContext channelHandlerContext, byte[] context) throws Exception {
        String commandId = MessageService.getCommandControl(context);
        Map<String,String> map = MessageService.analysisMessage(context, ServiceMessageEume.REGISTER.getUpLinePath());
        checkData(map);
        String pileNum = map.get("pileNum");
        pileNum = pileNum.substring(1,pileNum.length());
        String nowTime = DateUtils.now(DateUtils.yyMMddHHmmss);
        Map<String,String> dwn = new HashMap<>();
        dwn.put("time",nowTime);
        byte[] dwnContext = MessageService.getMessage(dwn,ServiceMessageEume.REGISTER.getDwnLinePath());
        ByteBuf pingMessage = Unpooled.buffer();
        // 判断是否已经有桩号进行过注册了
        if(SocketChannelMap.containsKey(pileNum)){
            String channelId = SocketChannelMap.getChannerId(pileNum);
            // 判断是否是同一个通道
            if (channelId.equals(channelHandlerContext.channel().id().toString())) {
                // 同一个通道，说明同一个桩在进行重复注册，返回成功
                pingMessage.writeBytes(dwnContext);
                channelHandlerContext.writeAndFlush(pingMessage);
                String msg = Util.BCD2String(dwnContext);
                LOGGER.info("客户端"+channelHandlerContext.channel().id()+",指令控制编号："+commandId+",桩编号:" + pileNum + "注册成功");
                LOGGER.info("客户端"+channelHandlerContext.channel().id()+",指令控制编号："+commandId+",桩编号:" + pileNum + ",注册下行信息" + msg);
                return new SocketResponseResult(channelHandlerContext, dwnContext);
            }else {
                // 跟原来的不是同一个通道，把之前的通道关闭，注销之前的注册
                String cid = SocketChannelMap.getChannerId(pileNum);
                ChannelHandlerContext cxt = (ChannelHandlerContext) SocketChannelMap.getChanneLContext(cid);
                SocketChannelMap.removeChannelMap(pileNum);
                cxt.close();
                LOGGER.info("关闭通道" + cid + ",桩编号" + pileNum);
            }
        }
        PileInfo pileInfo = getPileInfoByDeviceId(pileNum);
        if(pileInfo == null){
            throw new ServiceExcep(ServiceExceptionEume.EQPNOTREGISTERBACK);
        }
        // 获取桩的供电类型
        String powerType = map.get("powerType");
        pileInfo.setPowerType(powerType);
        pileInfo.setLastSurvivalTime(DateUtils.now());
        saveCache(channelHandlerContext,pileNum,pileInfo);
        pingMessage.writeBytes(dwnContext);
        channelHandlerContext.writeAndFlush(pingMessage);
        String msg = Util.BCD2String(dwnContext);
        LOGGER.info("客户端"+channelHandlerContext.channel().id()+",指令控制编号："+commandId+",桩编号:" + pileNum + "注册成功");
        LOGGER.info("客户端"+channelHandlerContext.channel().id()+",指令控制编号："+commandId+",桩编号:" + pileNum + ",注册下行报文" + msg);
        return new SocketResponseResult(channelHandlerContext,dwnContext);
    }

    @Override
    public SocketResponseResult execute(ChannelHandlerContext channelHandlerContext, Map data) throws Exception {
        return null;
    }

    /**
     * 保存缓存
     * @param channelHandlerContext 通道上细纹
     * @param pileNum 电桩号码
     * @param pileInfo 电桩信息
     */
    private void saveCache(ChannelHandlerContext channelHandlerContext,String pileNum,PileInfo pileInfo){
        SocketChannelMap.addChannelMap(channelHandlerContext.channel().id().toString(),pileNum,channelHandlerContext,pileInfo);
    }

    /**
     * 报文业务校验
     * @param map
     * @throws ServiceExcep
     */
    private void checkData(Map<String,String> map) throws ServiceExcep {
        if(map == null){
            throw new ServiceExcep(ServiceExceptionEume.MESSAGEPARSINGERROR);
        }
        if(!map.containsKey("pileNum")){
            throw new ServiceExcep(ServiceExceptionEume.INCOMPLETEPARAMETERS);
        }
        String pileNum = map.get("pileNum");
        if(StringUtils.isEmpty(pileNum)){
            throw new ServiceExcep(ServiceExceptionEume.INCOMPLETEPARAMETERS);
        }
        if(pileNum.length()<12){
            throw new ServiceExcep(ServiceExceptionEume.DEVICEIDERROR);
        }
    }

    /**
     * 请求后台，获取电桩信息
     * @param device_id
     * @return
     * @throws Exception
     */
    private PileInfo getPileInfoByDeviceId(String device_id) throws Exception {
        Map<String,Object> parMap = new HashMap<>();
        parMap.put("act","getPile");
        parMap.put("device_id",device_id);
        HttpResult result = httpAPIService.doPost(url,parMap);
        if(result.getCode() != 200){
            return null;
        }
        Map map = FastJsonUtils.stringToCollect(result.getBody());
        if(StringUtils.isEmpty(map.get("code")) || !"200".equals(map.get("code"))){
            return null;
        }
        if(StringUtils.isEmpty(map.get("data"))){
            return null;
        }
        JSONObject jsonObject = (JSONObject) map.get("data");
        PileInfo info = FastJsonUtils.toBean(jsonObject.toJSONString(),PileInfo.class);
        return info;
    }
}
